from .baseStates import (
    DataExpectState,
    DynamicDataState,
    StructExpectState,
    EncapsulatedState,
)

class GenericRect(StructExpectState):
    """State for yet undetermined encoding."""

    struct = (
        ("x-position", "U16"),
        ("y-position", "U16"),
        ("width", "U16"),
        ("height", "U16"),
        ("encoding-type", "S32"),
    )

    def act(self, client):
        _data = client.recvData(self.getDataSize(client))
        _rect = client.types.unpackDict(self.struct, _data)
        _cls = getEncoding(_rect["encoding-type"])
        return _cls(_rect)

class BaseEncoding(object):
    """Abstract encoding class"""

    id = None
    supported = False
    priority = None

    _rectProps = None

    def __init__(self, rectProps):
        self._rectProps = rectProps.copy()

class Raw(DataExpectState, BaseEncoding):

    id = 0
    supported = True
    priority = 0

    def getDataSize(self, client):
        return self._rectProps["width"] * \
            self._rectProps["height"] * client.types.calcsize((
                "PIXEL", ))

    def act(self, client):
        _data = client.recvData(self.getDataSize(client))
        _val = self._rectProps
        _val["data"] = _data
        client.setRawRect(_val)
        return None

class CopyRect(StructExpectState, BaseEncoding):

    id = 1
    supported = False
    priority = 10

    struct = (
        ("src-x", "U16"),
        ("src-y", "U16"),
    )

    def act(self, client):
        _data = client.recvData(self.getDataSize(client))
        _struct = client.types.unpackDict(self.struct, _data)
        _val = self._rectProps
        _val.update(_struct)
        client.copyRect(_val)

class RreEncoding(StructExpectState, BaseEncoding):

    id = 2
    supported = False # too slow in current wx-based implementation
    priority = 20

    struct = (
        ("subrect-count", "U32"),
        ("background", "PIXEL"),
    )

    def act(self, client):
        _data = client.recvData(self.getDataSize(client))
        _struct = client.types.unpackDict(self.struct, _data)
        _val = self._rectProps
        _val["colour"] = _struct["background"]
        client.fillRect(_val)
        return EncapsulatedState(
            states=[RreForeground() for _ii in xrange(
                _struct["subrect-count"])],
            lastState=None
        )

class RreForeground(StructExpectState):

    struct = (
        ("colour", "PIXEL"),
        ("x-position", "U16"),
        ("y-position", "U16"),
        ("width", "U16"),
        ("height", "U16"),
    )

    def act(self, client):
        _data = client.recvData(self.getDataSize(client))
        _val = client.types.unpackDict(self.struct, _data)
        client.fillRect(_val)

class CursorPseudo(DataExpectState, BaseEncoding):

    id = -239
    supported = True
    priority = 0

    def getCursorSize(self, client):
        return \
            self._rectProps["width"] * \
            self._rectProps["height"] * client.getBpp() \

    def getMaskSize(self, client):
        return \
            ((self._rectProps["width"] + 7) // 8) * \
            self._rectProps["height"]

    def getDataSize(self, client):
        return self.getCursorSize(client) + \
            self.getMaskSize(client)

    def act(self, client):
        _cursorData = client.recvData(self.getCursorSize(client))
        _maskData = client.recvData(self.getMaskSize(client))
        _val = self._rectProps
        client.setCursor(_val, _cursorData, _maskData)
        return None


allEncodings = (
    Raw,
    CopyRect,
    RreEncoding,
    CursorPseudo,
)

_encodingDict = dict((_el.id, _el) for _el in allEncodings)

def getEncoding(id):
    return _encodingDict[id]

def setEncodings(client):
    """Notify server about encodings supported in this module."""
    _supported = [_el for _el in allEncodings if _el.supported]
    _supported.sort(key=lambda el: el.priority, reverse=True)
    _supported = [_el.id for _el in _supported]
    # send header
    client.sendData(client.types.pack(
        ("U8", "x", "U16"),
        (2, len(_supported))
    ))
    # send encoding list
    client.sendData(client.types.pack(
        ("S32", ) * len(_supported),
        _supported
    ))

def getParser(count, tailState):
    """Return parser state for given amount of rectangles."""
    if count > 255:
        raise Exception("Are you insane? %s rectangles!" % count)
    return EncapsulatedState(
        states=[GenericRect() for _ii in xrange(count)],
        lastState=tailState
    )

# vim: set sts=4 sw=4 et :
